/**
 * 数据缓存管理工具类
 * 负责应用中数据的本地缓存、过期管理和性能优化
 */

import performanceConfig from '../config/performance.js';

class DataCache {
  constructor() {
    this.config = performanceConfig;
    this.memoryCache = new Map();
    this.storageKeyPrefix = this.config.cache.data.storageKeyPrefix;
    this.init();
  }
  
  /**
   * 初始化数据缓存管理器
   */
  init() {
    // 清理过期数据
    if (this.config.storage.local.clearExpiredData) {
      this.clearExpiredData();
    }
    
    // 定期清理任务
    this.scheduleCleanup();
    
    // 检查存储大小限制
    this.checkStorageSize();
  }
  
  /**
   * 设置缓存数据
   * @param {string} key - 缓存键
   * @param {any} data - 缓存数据
   * @param {Object} options - 缓存选项
   * @returns {Promise<boolean>} 是否成功
   */
  async set(key, data, options = {}) {
    try {
      const cacheTime = options.cacheTime || this.config.cache.data.defaultCacheTime;
      const storageType = options.storageType || 'memory'; // memory, local, session
      const compress = options.compress !== undefined ? options.compress : this.config.storage.local.compressData;
      const encrypt = options.encrypt !== undefined ? options.encrypt : this.config.storage.local.encryptSensitiveData;
      
      const cacheData = {
        data,
        timestamp: Date.now(),
        expireTime: cacheTime > 0 ? Date.now() + cacheTime : 0,
        compress,
        encrypt
      };
      
      // 内存缓存总是设置
      this.setMemoryCache(key, cacheData);
      
      // 根据存储类型设置持久化存储
      if (storageType === 'local') {
        await this.setLocalStorage(key, cacheData, compress, encrypt);
      } else if (storageType === 'session') {
        // 注意：在uni-app中，sessionStorage的支持可能有限
        #ifdef H5
        this.setSessionStorage(key, cacheData, compress, encrypt);
        #endif
      }
      
      return true;
    } catch (error) {
      console.error('设置缓存失败:', error);
      return false;
    }
  }
  
  /**
   * 获取缓存数据
   * @param {string} key - 缓存键
   * @param {Object} options - 获取选项
   * @returns {Promise<any|null>} 缓存数据或null
   */
  async get(key, options = {}) {
    try {
      const useMemoryCache = options.useMemoryCache !== false;
      const useStorageCache = options.useStorageCache !== false;
      
      // 优先从内存缓存获取
      if (useMemoryCache) {
        const memoryData = this.getMemoryCache(key);
        if (memoryData !== null) {
          return memoryData;
        }
      }
      
      // 从本地存储获取
      if (useStorageCache) {
        const storageData = await this.getLocalStorage(key);
        if (storageData !== null) {
          // 更新内存缓存
          this.setMemoryCache(key, {
            data: storageData,
            timestamp: Date.now(),
            expireTime: 0 // 从存储获取的数据不再设置过期时间
          });
          return storageData;
        }
      }
      
      return null;
    } catch (error) {
      console.error('获取缓存失败:', error);
      return null;
    }
  }
  
  /**
   * 删除缓存数据
   * @param {string} key - 缓存键
   * @returns {Promise<boolean>} 是否成功
   */
  async remove(key) {
    try {
      // 删除内存缓存
      this.memoryCache.delete(key);
      
      // 删除本地存储
      await uni.removeStorage({ key: this.getStorageKey(key) });
      
      // 删除会话存储
      #ifdef H5
      this.removeSessionStorage(key);
      #endif
      
      return true;
    } catch (error) {
      console.error('删除缓存失败:', error);
      return false;
    }
  }
  
  /**
   * 清空所有缓存
   * @returns {Promise<boolean>} 是否成功
   */
  async clear() {
    try {
      // 清空内存缓存
      this.memoryCache.clear();
      
      // 清空与本应用相关的本地存储
      const keys = await this.getAllStorageKeys();
      const appKeys = keys.filter(key => key.startsWith(this.storageKeyPrefix));
      
      await Promise.all(appKeys.map(key => uni.removeStorage({ key })));
      
      // 清空会话存储
      #ifdef H5
      this.clearSessionStorage();
      #endif
      
      return true;
    } catch (error) {
      console.error('清空缓存失败:', error);
      return false;
    }
  }
  
  /**
   * 设置内存缓存
   * @param {string} key - 缓存键
   * @param {Object} data - 缓存数据
   */
  setMemoryCache(key, data) {
    this.memoryCache.set(key, data);
    
    // 限制内存缓存大小
    if (this.memoryCache.size > 100) { // 限制100个条目
      this.evictOldestFromMemory();
    }
  }
  
  /**
   * 获取内存缓存
   * @param {string} key - 缓存键
   * @returns {any|null} 缓存数据或null
   */
  getMemoryCache(key) {
    const cacheData = this.memoryCache.get(key);
    
    if (!cacheData) {
      return null;
    }
    
    // 检查是否过期
    if (cacheData.expireTime > 0 && Date.now() > cacheData.expireTime) {
      this.memoryCache.delete(key);
      return null;
    }
    
    return cacheData.data;
  }
  
  /**
   * 从内存缓存中移除最旧的项
   */
  evictOldestFromMemory() {
    let oldestKey = null;
    let oldestTime = Infinity;
    
    for (const [key, value] of this.memoryCache.entries()) {
      if (value.timestamp < oldestTime) {
        oldestTime = value.timestamp;
        oldestKey = key;
      }
    }
    
    if (oldestKey) {
      this.memoryCache.delete(oldestKey);
    }
  }
  
  /**
   * 设置本地存储
   * @param {string} key - 缓存键
   * @param {Object} data - 缓存数据
   * @param {boolean} compress - 是否压缩
   * @param {boolean} encrypt - 是否加密
   */
  async setLocalStorage(key, data, compress, encrypt) {
    const storageKey = this.getStorageKey(key);
    let processedData = data;
    
    // 加密数据
    if (encrypt) {
      processedData = this.encryptData(processedData);
    }
    
    // 压缩数据
    if (compress) {
      processedData = this.compressData(processedData);
    }
    
    await uni.setStorage({ key: storageKey, data: processedData });
  }
  
  /**
   * 获取本地存储
   * @param {string} key - 缓存键
   * @returns {Promise<any|null>} 缓存数据或null
   */
  async getLocalStorage(key) {
    const storageKey = this.getStorageKey(key);
    
    try {
      const data = await uni.getStorage({ key: storageKey });
      
      if (!data || !data.data) {
        return null;
      }
      
      let processedData = data.data;
      
      // 解压缩数据
      if (processedData.compressed) {
        processedData = this.decompressData(processedData);
      }
      
      // 解密数据
      if (processedData.encrypted) {
        processedData = this.decryptData(processedData);
      }
      
      // 检查是否过期
      if (processedData.expireTime > 0 && Date.now() > processedData.expireTime) {
        await uni.removeStorage({ key: storageKey });
        return null;
      }
      
      return processedData.data;
    } catch (error) {
      // 键不存在
      return null;
    }
  }
  
  /**
   * 设置会话存储
   * @param {string} key - 缓存键
   * @param {Object} data - 缓存数据
   * @param {boolean} compress - 是否压缩
   * @param {boolean} encrypt - 是否加密
   */
  setSessionStorage(key, data, compress, encrypt) {
    const storageKey = this.getStorageKey(key);
    let processedData = data;
    
    if (encrypt) {
      processedData = this.encryptData(processedData);
    }
    
    if (compress) {
      processedData = this.compressData(processedData);
    }
    
    sessionStorage.setItem(storageKey, JSON.stringify(processedData));
  }
  
  /**
   * 删除会话存储
   * @param {string} key - 缓存键
   */
  removeSessionStorage(key) {
    const storageKey = this.getStorageKey(key);
    sessionStorage.removeItem(storageKey);
  }
  
  /**
   * 清空会话存储
   */
  clearSessionStorage() {
    const keys = Object.keys(sessionStorage);
    keys.forEach(key => {
      if (key.startsWith(this.storageKeyPrefix)) {
        sessionStorage.removeItem(key);
      }
    });
  }
  
  /**
   * 获取所有存储键
   * @returns {Promise<Array<string>>} 键数组
   */
  async getAllStorageKeys() {
    #ifdef H5
    return Object.keys(localStorage);
    #else
    // 在uni-app中，需要使用相应的API
    // 这里简化处理
    return [];
    #endif
  }
  
  /**
   * 获取存储键（添加前缀）
   * @param {string} key - 原始键
   * @returns {string} 带前缀的键
   */
  getStorageKey(key) {
    return `${this.storageKeyPrefix}${key}`;
  }
  
  /**
   * 压缩数据
   * @param {any} data - 原始数据
   * @returns {any} 压缩后的数据
   */
  compressData(data) {
    // 简单的压缩实现
    // 实际项目中可以使用更复杂的压缩算法
    return {
      ...data,
      compressed: true,
      compressedAt: Date.now()
    };
  }
  
  /**
   * 解压缩数据
   * @param {any} data - 压缩数据
   * @returns {any} 原始数据
   */
  decompressData(data) {
    const { compressed, compressedAt, ...rest } = data;
    return rest;
  }
  
  /**
   * 加密数据
   * @param {any} data - 原始数据
   * @returns {any} 加密后的数据
   */
  encryptData(data) {
    // 简单的加密实现
    // 实际项目中应该使用安全的加密算法
    return {
      ...data,
      encrypted: true,
      encryptedAt: Date.now()
    };
  }
  
  /**
   * 解密数据
   * @param {any} data - 加密数据
   * @returns {any} 原始数据
   */
  decryptData(data) {
    const { encrypted, encryptedAt, ...rest } = data;
    return rest;
  }
  
  /**
   * 清理过期数据
   */
  async clearExpiredData() {
    try {
      const keys = await this.getAllStorageKeys();
      const appKeys = keys.filter(key => key.startsWith(this.storageKeyPrefix));
      
      for (const key of appKeys) {
        try {
          const data = await uni.getStorage({ key });
          
          if (data && data.data && data.data.expireTime > 0 && Date.now() > data.data.expireTime) {
            await uni.removeStorage({ key });
          }
        } catch (error) {
          // 忽略单个键的错误
        }
      }
    } catch (error) {
      console.error('清理过期数据失败:', error);
    }
  }
  
  /**
   * 检查存储大小
   */
  async checkStorageSize() {
    try {
      // 估算存储大小
      const keys = await this.getAllStorageKeys();
      let totalSize = 0;
      
      for (const key of keys.filter(k => k.startsWith(this.storageKeyPrefix))) {
        try {
          const data = await uni.getStorage({ key });
          if (data && data.data) {
            totalSize += JSON.stringify(data.data).length;
          }
        } catch (error) {
          // 忽略单个键的错误
        }
      }
      
      // 如果超过限制，清理部分数据
      if (totalSize > this.config.storage.local.maxStorageSize) {
        await this.reduceStorageUsage();
      }
    } catch (error) {
      console.error('检查存储大小失败:', error);
    }
  }
  
  /**
   * 减少存储使用
   */
  async reduceStorageUsage() {
    // 清理最旧的数据
    // 这里简化实现
    await this.clearExpiredData();
  }
  
  /**
   * 安排定期清理任务
   */
  scheduleCleanup() {
    if (this.config.storage.local.clearExpiredData) {
      // 每24小时清理一次
      setInterval(() => {
        this.clearExpiredData();
      }, this.config.storage.local.clearInterval);
    }
  }
  
  /**
   * 获取缓存统计信息
   * @returns {Promise<Object>} 统计信息
   */
  async getCacheStats() {
    const memoryStats = {
      itemCount: this.memoryCache.size,
      oldestItem: this.getOldestMemoryItem()
    };
    
    const storageStats = {
      estimatedSize: 0,
      itemCount: 0
    };
    
    try {
      const keys = await this.getAllStorageKeys();
      const appKeys = keys.filter(key => key.startsWith(this.storageKeyPrefix));
      storageStats.itemCount = appKeys.length;
    } catch (error) {
      // 忽略错误
    }
    
    return {
      memory: memoryStats,
      storage: storageStats,
      totalCount: this.memoryCache.size + storageStats.itemCount
    };
  }
  
  /**
   * 获取内存缓存中最旧的项
   * @returns {Object|null} 最旧的项信息
   */
  getOldestMemoryItem() {
    let oldestKey = null;
    let oldestTime = Infinity;
    
    for (const [key, value] of this.memoryCache.entries()) {
      if (value.timestamp < oldestTime) {
        oldestTime = value.timestamp;
        oldestKey = key;
      }
    }
    
    if (oldestKey) {
      return {
        key: oldestKey,
        timestamp: oldestTime,
        age: Date.now() - oldestTime
      };
    }
    
    return null;
  }
  
  /**
   * 批量设置缓存
   * @param {Array<{key: string, data: any, options?: Object}>} items - 缓存项数组
   * @returns {Promise<Array<boolean>>} 结果数组
   */
  async bulkSet(items) {
    return Promise.all(items.map(item => this.set(item.key, item.data, item.options || {})));
  }
  
  /**
   * 批量获取缓存
   * @param {Array<{key: string, options?: Object}>} items - 获取项数组
   * @returns {Promise<Array<any>>} 结果数组
   */
  async bulkGet(items) {
    return Promise.all(items.map(item => this.get(item.key, item.options || {})));
  }
  
  /**
   * 批量删除缓存
   * @param {Array<string>} keys - 键数组
   * @returns {Promise<Array<boolean>>} 结果数组
   */
  async bulkRemove(keys) {
    return Promise.all(keys.map(key => this.remove(key)));
  }
}

// 导出单例
const dataCache = new DataCache();
export default dataCache;

// 导出缓存相关的工具函数
export const cacheUtils = {
  /**
   * 创建缓存键
   * @param {string} prefix - 前缀
   * @param {Object} params - 参数对象
   * @returns {string} 缓存键
   */
  createCacheKey(prefix, params = {}) {
    const sortedParams = Object.keys(params)
      .sort()
      .map(key => `${key}:${params[key]}`)
      .join('&');
    
    return `${prefix}${sortedParams ? `_${sortedParams}` : ''}`;
  },
  
  /**
   * 防抖函数
   * @param {Function} func - 要防抖的函数
   * @param {number} wait - 等待时间
   * @returns {Function} 防抖后的函数
   */
  debounce(func, wait = 300) {
    let timeout;
    return function executedFunction(...args) {
      const later = () => {
        clearTimeout(timeout);
        func(...args);
      };
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  },
  
  /**
   * 节流函数
   * @param {Function} func - 要节流的函数
   * @param {number} limit - 时间限制
   * @returns {Function} 节流后的函数
   */
  throttle(func, limit = 16) {
    let inThrottle;
    return function(...args) {
      if (!inThrottle) {
        func.apply(this, args);
        inThrottle = true;
        setTimeout(() => inThrottle = false, limit);
      }
    };
  },
  
  /**
   * 批量处理函数
   * @param {Array} items - 要处理的项目数组
   * @param {Function} processFn - 处理函数
   * @param {number} batchSize - 批次大小
   * @returns {Promise<Array>} 结果数组
   */
  async batchProcess(items, processFn, batchSize = 10) {
    const results = [];
    const batches = [];
    
    // 分割成批次
    for (let i = 0; i < items.length; i += batchSize) {
      batches.push(items.slice(i, i + batchSize));
    }
    
    // 逐个批次处理
    for (const batch of batches) {
      const batchResults = await Promise.all(batch.map(processFn));
      results.push(...batchResults);
    }
    
    return results;
  },
  
  /**
   * 延迟执行
   * @param {Function} fn - 要执行的函数
   * @param {number} delay - 延迟时间（毫秒）
   * @returns {Promise} 执行结果
   */
  delay(fn, delay = 0) {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(fn());
      }, delay);
    });
  },
  
  /**
   * 重试函数
   * @param {Function} fn - 要重试的函数
   * @param {Object} options - 重试选项
   * @returns {Promise<any>} 函数执行结果
   */
  async retry(fn, options = {}) {
    const {
      retries = 3,
      delay = 1000,
      exponential = true
    } = options;
    
    let lastError;
    
    for (let i = 0; i <= retries; i++) {
      try {
        return await fn();
      } catch (error) {
        lastError = error;
        
        if (i === retries) {
          throw error;
        }
        
        // 等待延迟
        const waitTime = exponential ? delay * Math.pow(2, i) : delay;
        await new Promise(resolve => setTimeout(resolve, waitTime));
      }
    }
    
    throw lastError;
  }
};

// 导出缓存策略
export const cacheStrategies = {
  /**
   * 获取API请求缓存策略
   * @param {string} url - 请求URL
   * @param {string} method - 请求方法
   * @returns {Object} 缓存策略
   */
  getApiCacheStrategy(url, method) {
    const config = performanceConfig;
    
    if (method !== 'GET') {
      return { enabled: false };
    }
    
    // 根据URL判断缓存时间
    let cacheTime = config.cache.data.defaultCacheTime;
    
    // 频繁变化的数据缓存时间较短
    if (url.includes('/api/real-time') || url.includes('/api/latest')) {
      cacheTime = 60 * 1000; // 1分钟
    }
    // 不常变化的数据缓存时间较长
    else if (url.includes('/api/static') || url.includes('/api/config')) {
      cacheTime = 60 * 60 * 1000; // 1小时
    }
    
    return {
      enabled: config.network.request.cacheGetRequests,
      cacheTime,
      storageType: 'local',
      compress: true,
      encrypt: url.includes('/api/sensitive')
    };
  },
  
  /**
   * 获取数据类型缓存策略
   * @param {string} dataType - 数据类型
   * @returns {Object} 缓存策略
   */
  getDataTypeCacheStrategy(dataType) {
    const config = performanceConfig;
    
    const strategies = {
      'user': {
        enabled: true,
        cacheTime: 5 * 60 * 1000,
        storageType: 'local',
        encrypt: true
      },
      'config': {
        enabled: true,
        cacheTime: 24 * 60 * 60 * 1000,
        storageType: 'local'
      },
      'temporary': {
        enabled: true,
        cacheTime: 5 * 60 * 1000,
        storageType: 'memory'
      },
      'search': {
        enabled: true,
        cacheTime: 30 * 60 * 1000,
        storageType: 'local'
      }
    };
    
    return strategies[dataType] || {
      enabled: true,
      cacheTime: config.cache.data.defaultCacheTime,
      storageType: 'local'
    };
  }
};